package edu.bbte;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

/**
 * Osztaly, amely segitsegevel tudunk fajlokba kocka kirakost irni. 
 *
 * @author      Robert Rill
 * @version     2011.0603
 * @since       1.6
 */
public class CubeRW {
	/**A fajlrendszer utvonala. Az osszes puzzle a files folderben talalhato. 
	 * Ebben van 4 ujabb folder: 3, 4, 5, 6 - a mereteknek megfeleloen. 
	 * Mindegyikben ezek kozul talalhato egy 0.txt nevo fajl. Ennek elso soraban van egy N szam,
	 * amely jelzi, hogy eddig hany kockakirakos szerepel az adott meretubol a folderben.
	 * Tovabba N folder van itten (1-tol N-ig szamozva), es mindegyikben egy-egy puzzle darabjai 
	 * illetve egy ujabb 0.txt fajl, mely elso soraban szinten egy szam: hany darabbol all a puzzle.
	 */
	private String directory = "../../files/";
	/**uj folder letrehozasa, mikor kiiratni szeretnenk puzzlet.*/
	private File folder;
	
	/**
	 * Konstruktor.
	 */
	public CubeRW() {
		
	}
		
	/**
	 * Folder letrehozasa.
	 * @param path - ez az utvonal, ahova a foldert szeretnenk letrehozni.
	 * 			   - tartalmazza a foldernevet is.
	 */
	private void createFolder(String path) {
		folder = new File(path);
		folder.mkdir();
	}
	
	/**
	 * A fajl elso soraban szereplo szam kiolvasasa, novelese eggyel es ennek elmentese a fajlba.
	 * @param file - a fajl neve, melyben a szamot modositani szeretnenk.
	 * @return - a fajlban szereplo szam eggyel novelve.
	 */
	private int increaseNumberInFile(String file) {
		try {
			int n;
			// fajl olvasasahoz szukseges readerek
			FileReader input = new FileReader(file);
			BufferedReader in = new BufferedReader(input);
			// beolvassuk a fajl elso sorat 
			String s  = in.readLine();
			// szamma alakitjuk az elso sort
			n = Integer.parseInt(s);			//elso sor a kocka merete			
			in.close();		
			// szam novelese
			++n;
			// fajl irasahoz szukseges writerek
			FileWriter output = new FileWriter(file);
			BufferedWriter out = new BufferedWriter(output);
			// beirjuk a novelt szamot az elso sorba
			out.write(Integer.toString(n));	
			out.close();
			return n;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}	
		return -1;
	}
	
	/**
	 * A fajl elso soraban szereplo szam kiolvasasa.
	 * @param file - a fajl neve, melybol a szamot olvassuk.
	 * @return - a fajlban szereplo szam.
	
	 */
	private int readNumberFromFile(String file) {
		// ugyanugy mukodik mint az elobbi metodus csak itt nem noveljuk a szamot
		try {
			int n;
			FileReader input = new FileReader(file);
			BufferedReader in = new BufferedReader(input);
			String s  = in.readLine();
			n = Integer.parseInt(s);			//elso sor a kocka merete			
			in.close();		
			return n;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}	
		return -1;
	}
	
	/**
	 * Szam beirasa a fajl elso soraba.
	 * @param file - a fajl neve, melybe a szamot irni szeretnenk.
	 * @param n - a szam, melyet a fajlba irni szeretnenk.
	 */
	public void writeNumberToFile(String file, int n) {
		try {
			// A fajl irasahoz szukseges writerek.
			FileWriter output = new FileWriter(file);
			BufferedWriter out = new BufferedWriter(output);
			out.write(Integer.toString(n));	//elso sor kocka merete + ures sor
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
	/**
	 * Metodus, mely kiiratja a kocka kirakos darabjait es a megoldast
	 * a megfelelo helyre.
	 * @param cubeList - a kirakando kocka darabjait tartalmazza.
	 * @param solution - a kirakott kocka darabjait tartalmazza.
	 */
	public void writePuzzle(Matrix3D [] cubeList, Matrix3D [] solution) {
		// lekerjuk a puzzle darabjainak szamat
		int n = cubeList.length;
		// lekerjuk a kockak meretet - ez alapjan dontjuk el, hogy a files folderben hova kerul a puzzle
		int size = cubeList[0].getSize();
		// a fajlrendszer utvonalat allitjuk a megfelelo meret folderere.
		String dir = directory + Integer.toString(size) + "/";
		// noveljuk ezen a helyen a 0.txt fajlban szereplo szamot, 
		//	  jelezve ezaltal, hogy eggyel tobb kocka kirakos kerult a fajlrendszerbe
		int m = this.increaseNumberInFile(dir + "0.txt");
		if (m == -1)
			return;
		// allitjuk az utvonalat az uj kiiratasi helyre
		dir = dir + Integer.toString(m);
		// letrahozzuk az ujabb puzzle szamara a foldert
		this.createFolder(dir);
		// beirjuk az aktualis puzzle darabjainak szamat a 0.txt fajlba
		this.writeNumberToFile(dir + "/0.txt", n);
		// egyenkent kiiratjuk a kirakos darabjait
		for (int i=0; i < n; ++i) {
			cubeList[i].writeCubeToFile(dir + "/g" +  (i+1) + ".txt");
		}
		
		if (size!=6) {  // ha n nem 6
		// egyenkent kiiratjuk a megoldott kirakos darabjait
			for (int i=0; i < n; ++i) {
				solution[i].writeCubeToFile(dir + "/s" +  (i+1) + ".txt");
			}
		}
	}
	
	/**
	 * Megadott meretu kocka kirakos kiolvasasa veletlenszeruen.
	 * @param size - a kocka merete, amilyent olvasni szeretnenk.
	 * @return - lista amely tartalmazza a kocka kirakos darabjait.
	 */
	public Matrix3D [] readRandomPuzzle(int size) {
		// allitjuk a fajlrendszer otvonalat a megadott meretu folderre
		String dir = directory + Integer.toString(size) + "/";
		// kiolvassuk a 0.txt fajlbol, hogy hany puzzle van eddig
		int n = this.readNumberFromFile(dir + "0.txt");
		// veletlenszeruen kivalasztunk egyet ezek kozul
		Random r = new Random();
		int m = r.nextInt(n) + 1;
		// allitjuk az otvonalat a megfelelo folderre
		dir = dir + Integer.toString(m) + "/";
		// kiolvassuk, hogy ebben a folderben a puzzle hany darabbol all
		n = this.readNumberFromFile(dir + "0.txt");
		// letrehozunk egy tombot a darabok tarolasara
		Matrix3D [] a = new Matrix3D[n];
		// megyunk vegig az allomanyokon es kiolvassuk a kocka kirakos darabjait
		for (int i=0; i<n; ++i) {
			a[i] = new Matrix3D(size);
			try {
				// letrahozzuk az i. darab tarolasara az objektumot
				a[i] = new Matrix3D(size);
				// kiolvassuk fajlbol a darabot
				a[i].readCubeFromFile(dir + "g" + (i+1) + ".txt");
			} catch (MatrixException e) {
				e.printStackTrace();
			}
		}
		return a;
	}
	
	/**
	 * Megadott utvonal alapjan kocka kirakos olvasunk a fajlrendszerbol.
	 * @param path - az utvonal ahonnakon olvasunk
	 * @param number - a kirakando kocka ennyi darabjainak szama
	 * @param size - a kirakando kocka merete
	 * @return - lista, mely tartalmazza a kockat
	 */
	public Matrix3D [] readPuzzleFromFile(String path, int number, int size) {
		int n = number;
		// letrehozzuk a tombot a kockak tarolasara
		Matrix3D [] a = new Matrix3D[n];
		// egyenkent kiolvassuk a darabokat
		for (int i=0; i<n; ++i) {
			a[i] = new Matrix3D(size);
			try {
				a[i] = new Matrix3D(size);
				a[i].readCubeFromFile(path + "/" + (i+1) + ".txt");
			} catch (MatrixException e) {
				e.printStackTrace();
			}
		}
		return a;
	}
	
//end of class
}
